home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d1 / freemacs.arc / SEARCH.ASM < prev    next >
Assembly Source File  |  1988-03-17  |  18KB  |  853 lines

  1. ;History:697,24,17
  2.     include    memory.def
  3.  
  4. data    segment    byte public
  5.  
  6. NULL    equ    0
  7.  
  8. b_struc    struc
  9. b    db    ?
  10. b_struc    ends
  11.  
  12. w_struc    struc
  13. w    dw    ?
  14. w_struc    ends
  15.  
  16. CHR    equ    "C"
  17. BOL    equ    "<"
  18. EOL    equ    ">"
  19. ANY    equ    "?"
  20. CCL    equ    "["
  21. ECCL    equ    "]"
  22. NCCL    equ    "~"
  23. EOS    equ    "."
  24. CLOSURE    equ    "*"
  25. CLOSIZE    equ    1
  26.  
  27.     extrn    outpat: byte
  28.     extrn    OUTPATSIZE: abs
  29.     extrn    inpat: byte
  30.     extrn    INPATSIZE: abs
  31. inpatlen    dw    ?
  32. direction    dw    ?
  33. slow_search    db    ?        ;=1 if we need to process magic chars.
  34.  
  35.     extrn    textseg: word
  36.  
  37. data    ends
  38.  
  39.  
  40. bufseg    segment    public
  41.  
  42.     extrn    topbot: word
  43.     extrn    bottop: word
  44.  
  45. bufseg    ends
  46.  
  47.  
  48. code    segment    byte public
  49.     assume    cs:code, ds:data
  50.  
  51.     public    slowly, forward, backward
  52.  
  53.  
  54.     extrn    get_mark: near, set_mark_si: near
  55.  
  56.     public    search
  57. search:
  58. ;enter with ch=start mark, cl=end mark, dh=first mark, dl=last mark.
  59. ;start searching at mark ch.  If the string is found, then return the
  60. ;  beginning in mark dh, and the end in mark dl, and cy=0.  If the string
  61. ;  wasn't found, return cy=1.
  62.     push    dx            ;save the first, last marks.
  63.     push    es
  64.     mov    es,textseg
  65.     assume    es:bufseg
  66.     push    ds            ;save ds
  67.     push    es
  68.     pop    ds
  69.     assume    ds:bufseg        ;for get_mark
  70.     mov    al,cl            ;get the end mark.
  71.     push    cx
  72.     call    get_mark
  73.     mov    di,si            ;save a copy of the end.
  74.     pop    cx
  75.     mov    al,ch            ;get the start mark.
  76.     call    get_mark
  77.     pop    ds            ;restore ds
  78.     assume    ds:data
  79.     mov    direction,0
  80.     cmp    si,di            ;start>=end?
  81.     jb    search_4        ;no.  (doesn't matter if they're equal)
  82.     mov    direction,1        ;yes, go in reverse direction.
  83. search_4:
  84.     cmp    slow_search,0        ;must we do a slow search?
  85.     jne    search_2        ;yes.
  86.     cmp    direction,0        ;search in proper direction.
  87.     jne    search_5
  88.     call    forward
  89.     jmp    search_3
  90. search_5:
  91.     call    backward
  92.     jmp    search_3
  93. search_2:
  94.     call    slowly
  95. search_3:
  96.     pop    es
  97.     assume    es:data
  98.     pop    dx
  99.     jc    search_1        ;not found.
  100.     push    ds
  101.     mov    ds,textseg        ;for set_mark_si
  102.     assume    ds:bufseg
  103.     push    bx            ;preserve pointer to end.
  104.     mov    al,dh
  105.     call    set_mark_si        ;set the first mark.
  106.     pop    si            ;pushed as bx.
  107.     mov    al,dl
  108.     call    set_mark_si        ;set the last mark.
  109.     pop    ds
  110.     assume    ds:data
  111.     clc                ;return a match.
  112.     ret
  113. search_1:
  114.     stc                ;return no match.
  115.     ret
  116.  
  117.  
  118.     public    regexp_pat
  119. regexp_pat:
  120. ;enter with si, cx->pattern.
  121. ;exit with cy=1 if error.
  122.     cmp    cx,INPATSIZE        ;too big?
  123.     jae    regexp_5        ;yes - return cy.
  124.     mov    di,offset inpat
  125.     rep    movsb
  126.     mov    al,NULL            ;store the terminating null.
  127.     stosb
  128.     call    makepat
  129.     jc    regexp_4        ;if any error, quit now.
  130. ;If outpat has only CHRs, we can use the fast search.  Fix up inpat so it
  131. ;  has the real string.  We must do this because of the '\' escape char.
  132.     mov    si,offset outpat
  133.     mov    di,offset inpat
  134.     mov    bp,di            ;make a copy of di.
  135. regexp_1:
  136.     lodsb
  137.     cmp    al,EOS            ;if we got to EOS, all is ok.
  138.     je    regexp_2
  139.     cmp    al,CHR            ;CHR?
  140.     jne    regexp_3        ;no - can't use fast search.
  141.     movsb                ;move the char to inpat.
  142.     jmp    regexp_1
  143. regexp_2:
  144.     sub    di,bp            ;subtract the base of the string.
  145.     mov    inpatlen,di        ;save the real length.
  146.     mov    slow_search,0
  147.     clc
  148.     jmp    short regexp_4
  149. regexp_3:
  150.     mov    slow_search,1
  151.     clc
  152. regexp_4:
  153.     ret
  154. regexp_5:
  155.     stc
  156.     ret
  157.  
  158.  
  159.  
  160.     public    literal_pattern
  161. literal_pattern:
  162. ;enter with si, cx->pattern.
  163. ;exit with cy=1 if error.
  164.     cmp    cx,INPATSIZE        ;too big?
  165.     jae    literal_3        ;yes - return cy.
  166.     push    si
  167.     push    cx
  168.     mov    inpatlen,cx
  169.     mov    di,offset inpat
  170.     rep    movsb
  171.     pop    cx
  172.     pop    si
  173.  
  174.     mov    di,offset outpat
  175.     jcxz    literal_1
  176. literal_2:
  177.     mov    ax,offset outpat-2
  178.     add    ax,OUTPATSIZE
  179.     cmp    di,ax            ;do we have enough room?
  180.     jae    literal_3        ;no - quit now.
  181.     mov    al,CHR
  182.     stosb
  183.     movsb
  184.     loop    literal_2
  185. literal_1:
  186.     mov    al,EOS            ;store the end of string.
  187.     stosb
  188.     mov    slow_search,0        ;we always use a fast search.
  189.     clc
  190.     ret
  191. literal_3:
  192.     stc
  193.     ret
  194.  
  195.  
  196.     assume    ds:data, es:bufseg
  197.  
  198. slowly:
  199. ;es:si -> first char to look at.
  200. ;es:di -> after last char to look at.
  201. ;return cy if no match, else nc, si->start of match, bx->after end of match.
  202. slowly_0:
  203.     cmp    si,topbot        ;at topbot already?
  204.     jne    slowly_1
  205.     mov    si,bottop
  206. slowly_1:
  207.     cmp    si,di            ;at the end yet?
  208.     stc                ;assume not found.
  209.     je    slowly_3        ;yes - not found.
  210.     push    di
  211.     mov    di,offset outpat    ;start at beginning of pattern.
  212.     call    amatch
  213.     pop    di            ;restore current, end.
  214.     jnc    slowly_3        ;we found a match
  215.     cmp    direction,0        ;forwards or backwards?
  216.     jne    slowly_2        ;backwards.
  217.     inc    si
  218.     cmp    si,topbot        ;at bottom of top?
  219.     jne    slowly_5        ;yes - load top of bottom.
  220.     mov    si,bottop
  221.     jmp    slowly_1
  222. slowly_5:
  223.     cmp    es:[si-1].w,LINENEW    ;at newline?
  224.     jne    slowly_1        ;no.
  225.     inc    si            ;yes - skip LF part of newline.
  226.     jmp    slowly_0
  227. slowly_2:
  228.     cmp    si,bottop        ;at top of bottom?
  229.     jne    slowly_4        ;no.
  230.     mov    si,topbot        ;yes - load bottom of top.
  231. slowly_4:
  232.     dec    si            ;back up to previous character.
  233.     cmp    si,bottop        ;at top of bottom now?
  234.     je    slowly_1        ;yes - can't possibly be split over newline.
  235.     cmp    es:[si-1].w,LINENEW    ;at newline?
  236.     jne    slowly_1        ;no.
  237.     dec    si            ;yes - skip to beginning of newline.
  238.     jmp    slowly_1
  239. slowly_3:
  240.     ret
  241.  
  242.  
  243. forward:
  244. ;es:si -> first char to look at.
  245. ;es:di -> after last char to look at.
  246. ;return cy if no match, else nc, si->start of match, bx->after end of match.
  247.     cmp    si,topbot        ;is start in bottom?
  248.     jne    forward_8        ;yes - no need to split.
  249.     mov    si,bottop
  250. forward_8:
  251.     cmp    di,bottop        ;is finish in top?
  252.     jne    forward_9        ;yes - no need to split.
  253.     mov    di,topbot
  254. forward_9:
  255.  
  256.     cmp    si,bottop        ;is start in bottom?
  257.     jae    forward_1        ;yes - no need to split.
  258.     cmp    di,topbot        ;is finish in top?
  259.     jbe    forward_1        ;yes - no need to split.
  260.     push    di
  261.     mov    di,topbot
  262.     call    forward            ;recursively search top
  263.     mov    ax,di
  264.     pop    di
  265.     jnc    forward_2        ;we found it - exit.
  266.     mov    si,ax            ;start where forward left off.
  267.     push    di
  268.     mov    di,bottop        ;and end where it will begin again.
  269.     call    slowly
  270.     pop    di
  271.     jnc    forward_2        ;they found it - exit.
  272.     mov    si,bottop        ;no need to save the old si.
  273.     call    forward
  274.     jmp    short forward_2        ;in any case, exit.
  275.  
  276. forward_1:
  277.     mov    cx,di            ;count the number of chars to look at.
  278.     sub    cx,si
  279.     mov    di,si            ;prepare for scasb.
  280.     mov    bx,inpatlen
  281.     dec    bx
  282.     sub    cx,bx            ;this many fewer chars to look at.
  283.     jb    forward_5        ;string is shorter than search.
  284. forward_3:
  285.     jcxz    forward_5        ;no chars to look at.
  286.     mov    si,offset inpat
  287.     lodsb                ;get the first char.
  288. forward_4:
  289.     scasb                ;look for the first char.
  290.     loopnz    forward_4        ;keep looking until we find it.
  291.     jnz    forward_5        ;we didn't
  292.     xchg    cx,bx            ;set the count to the string length.
  293.     push    cx            ;save the string length
  294.     push    di            ;save the source position
  295.     repe    cmpsb            ;is this it?
  296.     mov    cx,bx            ;restore the search length
  297.     pop    di            ;restore the source position
  298.     pop    bx            ;restore the string length
  299.     jne    forward_3        ;no match - try at next position.
  300.     cmp    inpat,LF        ;are we searching for an LF first string?
  301.     jne    forward_6        ;no - don't worry.
  302.     cmp    byte ptr es:[di-2],CR    ;did we just match the LF part of a newline?
  303.     je    forward_3        ;yes - no match.
  304. forward_6:
  305.     cmp    inpat[bx],CR        ;are we searching for a CR last string?
  306.     jne    forward_7        ;no - don't worry.
  307.     cmp    byte ptr es:[di+bx],LF    ;did we just match the CR part of a newline?
  308.     je    forward_3        ;yes - no match.
  309. forward_7:
  310.     mov    si,di            ;get the source position
  311.     add    bx,si            ;add it to the count to get the end.
  312.     dec    si            ;make it point to the first char again.
  313.     clc
  314.     jmp    short forward_2
  315. forward_5:
  316.     stc
  317. forward_2:
  318.     ret
  319.  
  320.  
  321. backward:
  322. ;es:si -> first char to look at.
  323. ;es:di -> after last char to look at.
  324. ;return cy if no match, else nc, si->start of match, bx->after end of match.
  325.     cmp    si,bottop        ;moving backwards, adjust topbot.
  326.     jne    backward_8
  327.     mov    si,topbot
  328. backward_8:
  329.     cmp    di,bottop        ;moving backwards, adjust topbot.
  330.     jne    backward_9
  331.     mov    di,topbot
  332. backward_9:
  333.     cmp    di,topbot        ;is finish in bottom?
  334.     ja    backward_1        ;yes - no need to split.
  335.     cmp    si,bottop        ;is start in top?
  336.     jb    backward_1        ;yes - no need to split.
  337.     push    di
  338.     mov    di,bottop
  339.     call    backward        ;recursively search top
  340.     mov    ax,di
  341.     pop    di
  342.     jnc    backward_2        ;we found it - exit.
  343.     mov    si,ax            ;start where backward left off.
  344.     push    di
  345.     mov    di,topbot        ;and end where backward will begin again.
  346.     call    slowly
  347.     pop    di
  348.     jnc    backward_2        ;they found it - exit.
  349.     mov    si,topbot        ;no need to save the old si.
  350.     call    backward
  351.     jmp    short backward_2    ;in any case, exit.
  352.  
  353. backward_1:
  354.     mov    cx,si            ;count the number of chars to look at.
  355.     sub    cx,di
  356.     mov    di,si            ;prepare for scasb.
  357.     mov    bx,inpatlen
  358.     dec    bx
  359.     sub    cx,bx            ;this many fewer chars to look at.
  360.     jb    backward_5        ;string is shorter than search.
  361.     sub    di,bx            ;back up that many chars.
  362.     add    di,2-1            ;pre-increment for loop and size.
  363. backward_3:
  364.     sub    di,2            ;restore next char.
  365.     jcxz    backward_5        ;no chars to look at.
  366.     mov    si,offset inpat
  367.     lodsb                ;get the first char.
  368.     std                ;now scan backwards.
  369. backward_4:
  370.     scasb                ;look for the first char.
  371.     loopnz    backward_4        ;keep looking until we find it.
  372.     cld                ;now compare, etc. forwards.
  373.     jnz    backward_5        ;we didn't find it.
  374.     add    di,2            ;go forwards to the next char.
  375.     xor    al,al            ;in case string length-1=0.
  376.     xchg    cx,bx            ;set the count to the string length.
  377.     push    cx            ;save the string length
  378.     push    di            ;save the source position
  379.     repe    cmpsb            ;is this it?
  380.     mov    cx,bx            ;restore the search length
  381.     pop    di            ;restore the source position
  382.     pop    bx            ;restore the string length
  383.     jne    backward_3        ;no match - try at next position.
  384.     cmp    inpat,LF        ;are we searching for an LF first string?
  385.     jne    backward_6        ;no - don't worry.
  386.     cmp    byte ptr es:[di-2],CR    ;did we just match the LF part of a newline?
  387.     je    backward_3        ;yes - no match.
  388. backward_6:
  389.     cmp    inpat[bx],CR        ;are we searching for a CR last string?
  390.     jne    backward_7        ;no - don't worry.
  391.     cmp    byte ptr es:[di+bx],LF    ;did we just match the CR part of a newline?
  392.     je    backward_3        ;yes - no match.
  393. backward_7:
  394.     mov    si,di            ;get the source position
  395.     add    bx,si            ;add it to the count to get the end.
  396.     dec    si            ;make it point to the first char again.
  397.     clc
  398.     jmp    short backward_2
  399. backward_5:
  400.     stc
  401. backward_2:
  402.     ret
  403.  
  404.  
  405. amatch:
  406. ;es:si -> source text
  407. ;ds:di -> pattern
  408. ;return cy if no match, else nc, bx->end of matching string
  409.     push    si            ;preserve input pointers.
  410.     push    di
  411. amatch_1:
  412.     mov    al,[di]
  413.     cmp    al,EOS
  414.     mov    bx,si            ;prepare to exit.
  415.     je    amatch_success
  416.     cmp    al,CLOSURE
  417.     jne    amatch_3
  418.     add    di,CLOSIZE
  419.     mov    bx,si            ;save the first closure pattern.
  420. ;match as many as we can
  421. amatch_4:
  422.     call    omatch
  423.     jnc    amatch_4
  424. ;match only as many as fit the next pattern
  425.     call    patsiz
  426.     add    di,ax
  427. amatch_5:
  428.     push    bx
  429.     call    amatch            ;try to match rest of pattern.
  430.     pop    ax            ;conserve stack
  431.     jnc    amatch_success        ;go if it matched.
  432.     mov    bx,ax            ;restore bx.
  433.     cmp    si,bottop        ;backing up past the point?
  434.     jne    amatch_8        ;no - just decrement.
  435.     mov    si,topbot        ;yes - get the bottom of the top.
  436. amatch_8:
  437.     dec    si            ;point to the previous character.
  438.     cmp    si,bx            ;zero or more matches still?
  439.     jae    amatch_5        ;yes.
  440.     stc
  441.     jmp    short amatch_exit    ;can't get rest of pattern to match.
  442. amatch_3:
  443.     call    omatch
  444.     jc    amatch_exit        ;unsuccessful - exit.
  445. amatch_7:
  446.     call    patsiz
  447.     add    di,ax
  448.     jmp    amatch_1
  449. amatch_success:
  450.     clc
  451. amatch_exit:
  452.     pop    di            ;restore input pointers.
  453.     pop    si
  454.     ret
  455.  
  456.  
  457. omatch:
  458. ;omatch matches at most one character, and only if it returns true at
  459. ;  omatch_yes.  When we get to omatch_yes, we see if we are at the point.
  460. ;es:si -> source text
  461. ;ds:di -> pattern
  462.     mov    al,[di]
  463.     cmp    al,CHR
  464.     jne    omatch_1
  465.     mov    al,es:[si]
  466.     cmp    al,[di+1]
  467.     jne    omatch_no
  468.     inc    si
  469.     jmp    omatch_yes
  470. omatch_1:
  471.     cmp    al,BOL
  472.     jne    omatch_2
  473.     cmp    si,bottop        ;are we at the point?
  474.     jne    omatch_1_1        ;no.
  475.     push    si            ;yes - have to look at the top.
  476.     mov    si,topbot
  477.     cmp    es:[si-2].w,LINENEW
  478.     pop    si
  479.     jne    omatch_no
  480.     jmp    omatch_yes
  481. omatch_1_1:
  482.     cmp    es:[si-2].w,LINENEW
  483.     jne    omatch_no
  484.     jmp    omatch_yes
  485. omatch_2:
  486.     cmp    al,EOL
  487.     jne    omatch_3
  488.     cmp    es:[si].w,LINENEW
  489.     jne    omatch_no
  490.     jmp    omatch_yes
  491. omatch_3:
  492.     cmp    al,ANY
  493.     jne    omatch_4
  494.     cmp    es:[si].w,LINENEW
  495.     je    omatch_no
  496.     inc    si
  497.     jmp    omatch_yes
  498. omatch_4:
  499.     cmp    al,CCL
  500.     jne    omatch_5
  501.     cmp    es:[si].w,LINENEW
  502.     je    omatch_no
  503.     call    locate
  504.     jc    omatch_no
  505.     inc    si
  506.     jmp    omatch_yes
  507. omatch_5:
  508.     cmp    al,NCCL
  509.     jne    omatch_6
  510.     cmp    es:[si].w,LINENEW
  511.     je    omatch_no
  512.     call    locate
  513.     jnc    omatch_no
  514.     inc    si
  515.     jmp    omatch_yes
  516. omatch_6:
  517. ;error
  518.     jmp    omatch_no
  519. omatch_no:
  520.     stc
  521.     ret
  522. omatch_yes:
  523.     cmp    si,topbot        ;at bottom of top?
  524.     jne    omatch_yes_1
  525.     mov    si,bottop        ;yes, go to top of bottom.
  526. omatch_yes_1:
  527.     clc
  528.     ret
  529.  
  530.  
  531. locate:
  532. ;es:si -> search string
  533. ;ds:di -> CCL
  534. ;exit with cy=0 if found.
  535.     push    cx
  536.     mov    cl,[di+1]        ;get the count.
  537.     mov    ch,0
  538.     mov    al,es:[si]
  539.     push    es            ;save es, di
  540.     push    di
  541.     push    ds            ;outpat is in ds
  542.     pop    es
  543.     add    di,2            ;di now -> characters.
  544.     repne    scasb
  545.     pop    di            ;restore es,di
  546.     pop    es
  547.     pop    cx
  548.     jne    locate_1
  549.     clc
  550.     ret
  551. locate_1:
  552.     stc
  553.     ret
  554.  
  555.  
  556. patsiz:
  557. ;enter ds:di -> pat
  558.     mov    al,[di]
  559.     cmp    al,CHR
  560.     jne    patsiz_1
  561.     mov    ax,2
  562.     ret
  563. patsiz_1:
  564.     cmp    al,CLOSURE
  565.     jne    patsiz_2
  566.     mov    ax,CLOSIZE
  567.     ret
  568. patsiz_2:
  569.     cmp    al,BOL
  570.     je    patsiz_3
  571.     cmp    al,EOL
  572.     je    patsiz_3
  573.     cmp    al,ANY
  574.     jne    patsiz_4
  575. patsiz_3:
  576.     mov    ax,1
  577.     ret
  578. patsiz_4:
  579.     cmp    al,CCL
  580.     je    patsiz_5
  581.     cmp    al,NCCL
  582.     jne    patsiz_6
  583. patsiz_5:
  584.     mov    al,[di+1]
  585.     mov    ah,0
  586.     add    ax,2
  587.     ret
  588. patsiz_6:
  589. ;error
  590.     ret
  591.  
  592.     assume    ds:data, ds:data
  593.  
  594.     public    eol_only
  595. eol_only:
  596. ;return zr if the search pattern matches eol only.
  597. ;  we need this routine because search and replace should advance past the
  598. ;  newline if we're matching eol only.
  599.     cmp    word ptr outpat,EOS*256 + EOL
  600.     ret
  601.  
  602.  
  603. makepat:
  604. ;si -> source pat (null terminated)
  605. ;di -> dest pattern, dx -> last dest entry.
  606. ;bx -> last closure
  607. ;return cy=1 if error.
  608.     mov    si,0
  609.     mov    di,0
  610.     mov    dx,OUTPATSIZE
  611.     mov    bx,-1
  612. makepat_1:
  613.     cmp    inpat[si],NULL
  614.     je    makepat_0
  615.     push    di
  616.     mov    al,inpat[si]
  617.     cmp    al,'\'            ;are we escaping something?
  618.     jne    makepat_a
  619.     cmp    inpat[si+1],NULL    ;is the '\' at the end?
  620.     je    makepat_9        ;yes - just use \.
  621.     inc    si
  622.     mov    al,inpat[si]        ;get the escaped char.
  623.     jmp    makepat_9        ;go stick it in.
  624. makepat_a:
  625.     cmp    al,ANY
  626.     jne    makepat_3
  627.     call    addset
  628.     jmp    makepat_2
  629. ;this really belongs at the end of makepat, but the short jump can't get there.
  630. makepat_0:
  631.     mov    al,EOS
  632.     call    addset
  633.     cmp    di,dx
  634.     jne    makepat__0_1
  635.     stc
  636.     ret
  637. makepat__0_1:
  638.     clc
  639.     ret
  640. makepat_3:
  641.     cmp    al,BOL
  642.     jne    makepat_7
  643.     cmp    si,0
  644.     jne    makepat_6
  645.     call    addset
  646.     jmp    makepat_2
  647. makepat_6:
  648.     call    addchar
  649.     jmp    makepat_2
  650. makepat_7:
  651.     cmp    al,EOL
  652.     jne    makepat_8
  653.     cmp    inpat[si+1],NULL
  654.     jne    makepat_9
  655.     call    addset
  656.     jmp    makepat_2
  657. makepat_9:
  658.     call    addchar
  659.     jmp    makepat_2
  660. makepat_8:
  661.     cmp    al,CCL
  662.     jne    makepat_10
  663.     call    getccl
  664.     jnc    makepat_2
  665.     pop    di
  666.     stc
  667.     ret
  668. makepat_10:
  669.     cmp    al,CLOSURE
  670.     jne    makepat_11
  671.     cmp    bx,0            ;is bx>0?
  672.     jnge    makepat_12        ;no - not closure.
  673.     mov    al,outpat[bx]
  674.     cmp    al,CLOSURE        ;trying to close a closure?
  675.     je    makepat_12        ;yes - not closure.
  676.     cmp    al,BOL            ;trying to close a beginning of line?
  677.     je    makepat_12        ;yes - not closure.
  678.     call    stclos
  679.     add    sp,2            ;throw away the old previous.
  680.     push    bx
  681.     jmp    makepat_2
  682. makepat_11:
  683.     cmp    al,NCCL
  684.     jne    makepat_13
  685.     cmp    inpat[si+1],NULL    ;not special at the end.
  686.     je    makepat_13
  687.     mov    al,NCCL
  688.     call    addset
  689.     mov    al,1            ;one character follows.
  690.     call    addbyte
  691.     mov    al,inpat[si+1]
  692.     call    addbyte
  693.     inc    si            ;skip the NCCL.
  694.     jmp    makepat_2
  695. makepat_13:
  696. makepat_12:
  697.     call    addchar
  698.     jmp    makepat_2
  699. makepat_2:
  700.     pop    bx
  701.     inc    si
  702.     jmp    makepat_1
  703.  
  704.  
  705. addchar:
  706. ;al = CHR to put.
  707.     push    ax
  708.     mov    al,CHR
  709.     call    addset
  710.     pop    ax
  711.     call    addbyte
  712.     ret
  713.  
  714.  
  715. addset:            ;only command chars call addset.
  716. addbyte:
  717. ;al = char to put, di->dest, dx->end of dest.
  718.     cmp    di,dx
  719.     je    addbyte_1
  720.     mov    outpat[di],al
  721.     inc    di
  722. addbyte_1:
  723.     ret
  724.  
  725.  
  726. stclos:
  727. ;si->last set added + 1
  728. ;bx-> last closure added
  729.     push    di
  730. stclos_1:
  731.     dec    di
  732.     mov    al,outpat[di]
  733.     mov    outpat[di+CLOSIZE],al
  734.     cmp    di,bx
  735.     jne    stclos_1
  736. stclos_2:
  737.     mov    outpat[bx],CLOSURE
  738.     pop    di
  739.     add    di,CLOSIZE
  740.     ret
  741.  
  742.  
  743. getccl:
  744. ;si -> source (null terminated)
  745. ;di -> dest, dx -> end of dest
  746. ;return cy=1 if error.
  747.     inc    si
  748.     mov    al,inpat[si]
  749.     cmp    al,NCCL
  750.     jne    getccl_1
  751.     call    addset
  752.     inc    si
  753.     jmp    getccl_2
  754. getccl_1:
  755.     mov    al,CCL
  756.     call    addset
  757. getccl_2:
  758.     push    bx
  759.     mov    bx,di
  760.     call    addbyte            ;leave room for count
  761.     call    dodash
  762.     mov    ax,di
  763.     sub    ax,bx
  764.     dec    ax
  765.     mov    outpat[bx],al
  766.     pop    bx
  767.     cmp    inpat[si],ECCL
  768.     je    getccl_3
  769.     stc
  770.     ret
  771. getccl_3:
  772.     clc
  773.     ret
  774.  
  775.  
  776. dodash:
  777. ;si -> source pattern (null terminated)
  778. ;di -> destination pattern
  779. ;dx -> end of destination pattern
  780.     push    bx
  781.     mov    bx,si
  782. dodash_1:
  783.     mov    al,inpat[si]
  784.     or    al,al
  785.     je    dodash_2
  786.     cmp    al,ECCL
  787.     je    dodash_2
  788.     cmp    al,"-"
  789.     je    dodash_4
  790.     call    addbyte
  791.     jmp    dodash_8
  792. dodash_4:
  793.     cmp    si,bx            ;at beginning?
  794.     je    dodash_5
  795.     cmp    inpat[si],NULL        ;or at end?
  796.     jne    dodash_6
  797. dodash_5:
  798.     mov    al,"-"            ;if at beginning or at end, just a "-"
  799.     call    addbyte
  800.     jmp    dodash_8
  801. dodash_6:
  802.     mov    al,inpat[si-1]
  803.     cmp    al,inpat[si+1]
  804.     ja    dodash_5
  805.     call    alphanumeric
  806.     jnc    dodash_5
  807.     mov    al,inpat[si+1]
  808.     call    alphanumeric
  809.     jnc    dodash_5
  810.     mov    al,inpat[si-1]
  811. dodash_7:
  812.     inc    al            ;pre-increment -- the first one's there.
  813.     cmp    al,inpat[si+1]
  814.     ja    dodash_9
  815.     call    addbyte
  816.     jmp    dodash_7
  817. dodash_9:
  818.     inc    si
  819. dodash_8:
  820.     inc    si
  821.     jmp    dodash_1
  822. dodash_2:
  823.     pop    bx
  824.     ret
  825.  
  826.  
  827. alphanumeric:
  828. ;return cy=1 if al is alphanumeric
  829.     cmp    al,"0"
  830.     jb    alphanumeric_1
  831.     cmp    al,"9"
  832.     jbe    alphanumeric_2
  833.     cmp    al,"A"
  834.     jb    alphanumeric_1
  835.     cmp    al,"Z"
  836.     jbe    alphanumeric_2
  837.     cmp    al,"a"
  838.     jb    alphanumeric_1
  839.     cmp    al,"z"
  840.     jbe    alphanumeric_2
  841. alphanumeric_1:
  842.     clc
  843.     ret
  844. alphanumeric_2:
  845.     stc
  846.     ret
  847.  
  848.  
  849. code    ends
  850.  
  851.     end
  852.  
  853.